webpack require.ensure

webpack 异步加载(代码切割)的原理

webpack 一般是把所有js模块都打包到一个.js文件,然后在页面加载时请求这个文件。但是,有些js模块的功能并不需要在页面加载时生效(例如按钮点击触发的操作),因此可以把这类js模块独立导出一个.js文件(chunk)。当使用这个模块的时候,webpack 会构造 script dom 元素,由浏览器发起异步请求,去获得这个js文件(jsonp形式)。

例如:

1
2
3
4
5
6
7
8
9
10
11
mapBtn.click(function() {
//获取 文档head对象
var head = document.getElementsByTagName('head')[0];
//构建 <script>
var script = document.createElement('script');
//设置src属性
script.async = true;
script.src = "http://map.baidu.com/.js";
//加入到head对象中
head.appendChild(script);
})

webpack api 实现方式:

1
2
3
4
5
mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require('./baidumap.js');
})
})

另外,ensure 会把没有使用过的 require 资源独立分成一个js文件,而对于同步的 require 会忽略:

1
2
3
4
5
6
7
8
var sync = require('syncdemo.js')   //下面ensure里面也用到
mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require('./baidumap.js');
// 异步里面再导入同步模块,实际是使用已经加载到模块缓存中的同步中的模块,因此打包时这个模块不会独立出去
var sync = require('syncdemo.js');
})
})

资料博客

require.ensure 的参数解析(webpack 2.2)

require.ensure(dependencies: String[], callback: function(require), chunkName: String)

  • dependencies

    依赖,回调函数被执行前需要加载完成的模块。

  • callback

    回调函数,当所有的依赖都加载完成后,执行这个回调函数。

    require对象的一个实现会作为一个参数传递给这个回调函数,因此可以进一步 require() 依赖模块。

  • chunkName

    定义 chunk 名称, 即被打包进的.js文件名称。

    多个 require.ensure 具有相同的 chunkName 参数,则这些异步请求的依赖会被打包进同一个文件束(bundle)。

资料站点

一些使用情况

模块文件:

1
2
3
4
5
6
7
8
9
10
11
// a.js
console.log('***** I AM a *****');
module.exports = "A part";

// b.js
console.log('***** I AM b *****');
module.exports = "B part";

// c.js
console.log('***** I AM c *****');
module.exports = "C part";

入口文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// entry.js
// 页面加载时,console 与 alert 输出A信息
var a = require('./a.js');
alert(a);

// 情况一:
// webpack打包时,A模块与B模块分开打包
// 点击按钮时,加载B模块,console B信息,先后 alert B和A的信息
document.getElementById("Btn").onclick = function() {
require.ensure([], function() {
var b = require('./b.js');
alert(b);
var a2 = require('./a.js');
alert(a2);
})
}

// 情况二:
// webpack打包时,B和C模块被打包在一起,成为merge.js
// 点击按钮时,仅加载 merge 模块,console 与 alert 均无输出,即 merge 模块仅为可使用状态,没有实际输出
document.getElementById("Btn").onclick = function() {
require.ensure(['./b.js'], function(){}, 'merge');
require.ensure(['./c.js'], function(){}, 'merge');
}

// 情况三:
// webpack打包时,B和C模块被打包在一起
// 点击按钮时,模块加载,但仅C模块部分被执行,B模块部分仅为可使用状态
// 异步加载,输出顺序为:console A, alert A, console C, alert C
document.getElementById("Btn").onclick = function() {
require.ensure(['./b.js'], function(){
var c = require('./c.js');
alert(c);
})
alert(a);
}